home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Mac OS X Throbber / Source / MultiMonitorApp.cp < prev    next >
Encoding:
Text File  |  2000-06-24  |  11.0 KB  |  428 lines

  1. // ===========================================================================
  2.  
  3. #include "MultiMonitorApp.h"
  4.  
  5. #include <PP_DebugMacros.h>
  6.  
  7. #include <LGrowZone.h>
  8. #include <PP_Messages.h>
  9. #include <PP_Resources.h>
  10. #include <UDrawingState.h>
  11. #include <UMemoryMgr.h>
  12. #include <URegistrar.h>
  13. #include <UEnvironment.h>
  14. #include <UAttachments.h>
  15. #include <LDocument.h>
  16. #include <LMenuBar.h>
  17. #include <LModelDirector.h>
  18. #include <UScreenPort.h>
  19. #include <LComparator.h>
  20. #include <LCMAttachment.h>
  21. #include <UCMMUtils.h>
  22. #include <LUndoer.h>
  23. #include <LMenu.h>
  24. #include <UDesktop.h>
  25.  
  26. #include <UStandardDialogs.h>
  27. #if PP_StdDialogs_Option == PP_StdDialogs_Conditional
  28.     #include <UConditionalDialogs.h>
  29. #endif
  30.  
  31. #include <UControlRegistry.h>
  32.  
  33. #include <LDebugStream.h>
  34.  
  35. #include <UDebugNew.h>
  36. #include <UDebugUtils.h>
  37. #include <UHeapUtils.h>
  38. #include <UMemoryEater.h>
  39. #include <UOnyx.h>
  40. #include <UProcess.h>
  41. #include <UVolume.h>
  42.  
  43. #if PP_Debug
  44.     #include <LSIOUXAttachment.h>        // Only needed for LDebugStream
  45.     
  46.     #include <LDebugMenuAttachment.h>
  47.     #include <LCommanderTree.h>
  48.     #include <LPaneTree.h>
  49.     #include <LTreeWindow.h>
  50. #endif
  51.  
  52. #include <LWindow.h>
  53. #include <LPrintout.h>
  54. #include <LPlaceHolder.h>
  55.  
  56. #include "MultiMonitorDoc.h"
  57. #include "MultiMonitorController.h"
  58.  
  59. #include <Appearance.h>
  60.  
  61. #if PP_Debug
  62.     #include "MetroNubUtils.h"
  63. #endif
  64.  
  65. #include <new>
  66.  
  67. #include "UMiscUtils.h"
  68.  
  69. // ---------------------------------------------------------------------------
  70. //    Prototypes
  71.  
  72. void    AppMain();        // main loop
  73. void    PP_NewHandler() throw (PP_STD::bad_alloc);    // defined in PPDebug_New.cp
  74.  
  75. const CommandT    cmd_DoTest                        = FOUR_CHAR_CODE('teSt');
  76.  
  77.  
  78. // ===========================================================================
  79. //    • main
  80. // ===========================================================================
  81.  
  82. int main()
  83. {
  84.         // First things first. Install a new_handler.
  85.     (void)PP_STD::set_new_handler(PP_NewHandler);
  86.     
  87.         // Don't let exceptions propagate outside of main
  88.     try {
  89.         AppMain();
  90.     } catch (...) {
  91.         SignalStringLiteral_("Exception caught in main");
  92.     }
  93.     
  94.     return 0;
  95. }
  96.  
  97.  
  98. // ---------------------------------------------------------------------------
  99. //    • AppMain
  100. // ---------------------------------------------------------------------------
  101.  
  102. void AppMain()
  103. {
  104. #if PP_Debug
  105.  
  106.         // If under the debugger, use the debugger for everything
  107.         // (throw, signal, DebugNew), else use alerts.
  108.     
  109.     if (AmIBeingMWDebugged()) {
  110.  
  111.         UDebugging::SetDebugThrow(debugAction_Debugger);
  112.         UDebugging::SetDebugSignal(debugAction_Debugger);
  113.  
  114.     } else {
  115.  
  116.             // Not under the MW Debug, so use alerts. If you use
  117.             // another debugger, you could set this up the same way. Point
  118.             // is to use the debugger's facilities when under the debugger,
  119.             // else alerts.
  120.         
  121.         UDebugging::SetDebugThrow(debugAction_Alert);
  122.         UDebugging::SetDebugSignal(debugAction_Alert);
  123.  
  124.             // Use our own error handler for DebugNew which uses alerts
  125.             // instead of DebugStr calls.
  126.     
  127.         PP_DebugNewInstallPPErrorHandler_();
  128.     }
  129.  
  130. #else
  131.         // In final build mode so nothing should be seen. These are
  132.         // commented out because gDebugThrow and gDebugSignal are
  133.         // initialized to debugAction_Nothing -- assignment here is
  134.         // unnecessary (but left in as a comment for illustration).
  135.     
  136.     UDebugging::SetDebugThrow(debugAction_Nothing);
  137.     UDebugging::SetDebugSignal(debugAction_Nothing);
  138.     
  139. #endif    
  140.  
  141.         // Clean up any "leaks" that might have occured at static
  142.         // initialization time.
  143.     {
  144.         SLResetLeaks_();
  145.         DebugNewForgetLeaks_();
  146.     }
  147.  
  148.  
  149.         // Normal initializations
  150.     InitializeHeap(5);
  151.     UQDGlobals::InitializeToolbox(&qd);
  152.     ::InitCursor();
  153.     ::FlushEvents(everyEvent, nil);
  154.     
  155.         // Check Debugging environment
  156. #if PP_Debug
  157.     UDebugUtils::CheckEnvironment();
  158. #endif
  159.     
  160.         // Install a GrowZone to catch low-memory situations    
  161.     LGrowZone* theGZ = NEW LGrowZone(20000);
  162.     ValidateObject_(theGZ);
  163.     SignalIf_(theGZ->MemoryIsLow());
  164.  
  165.         // Create the application object and run. The scope of
  166.         // the object is limited as we need to control when
  167.         // the object's destructor is called (in relation to
  168.         // the code that follows it).
  169.     {
  170.         MultiMonitorApp    theApp;
  171.         theApp.Run();
  172.     }
  173.         
  174. #if PP_Debug
  175.  
  176.         // This cleanup isn't necessary (they are items that are to
  177.         // remain for the duration of the application's run time. When
  178.         // the app quits and the Process Manager reclaims the heap,
  179.         // the memory occupied by these items will be released). This
  180.         // is just done to keep things like DebugNew and Spotlight
  181.         // quiet.
  182.     
  183.     LMenuBar*    theBar = LMenuBar::GetCurrentMenuBar();
  184.     delete theBar;
  185.  
  186.     URegistrar::DisposeClassTable();
  187.  
  188.     LPeriodical::DeleteIdlerAndRepeaterQueues();
  189.  
  190.     UMemoryEater::DeleteMemoryLists();
  191.  
  192.     LModelDirector*    theDirector = LModelDirector::GetModelDirector();
  193.     delete theDirector;
  194.  
  195.     LModelObject::DestroyLazyList();
  196.  
  197.     UScreenPort::Dispose();
  198.     
  199.     LComparator*    theCompare = LComparator::GetComparator();
  200.     delete theCompare;
  201.     
  202.     LLongComparator*    theLongCompare = LLongComparator::GetComparator();
  203.     delete theLongCompare;
  204.  
  205.     DisposeOf_(theGZ);
  206.     
  207. #endif
  208.  
  209.     DebugNewReportLeaks_();
  210. }
  211.  
  212.  
  213. // ---------------------------------------------------------------------------
  214. //    • MultiMonitorApp                                    [public]
  215. // ---------------------------------------------------------------------------
  216. //    Application object constructor
  217.  
  218. MultiMonitorApp::MultiMonitorApp()
  219. {
  220.         // Register ourselves with the Appearance Manager
  221.     if (UEnvironment::HasFeature(env_HasAppearance)) {
  222.         ::RegisterAppearanceClient();
  223.     }
  224.  
  225.     RegisterClasses();
  226.     
  227.         // Preload facilities for the Standard Dialogs
  228.     PP_StandardDialogs::Load();
  229.     
  230.         // Require at least Navigation Services 1.1. See comments
  231.         // above SetTryNavServices in UConditionalDialogs.cp for why
  232.         // you might wish to do this.
  233. #if PP_StdDialogs_Option == PP_StdDialogs_Conditional
  234.     UConditionalDialogs::SetTryNavServices(0x01108000);
  235. #endif
  236.  
  237.         // Initialize contextual menus
  238.     UCMMUtils::Initialize();
  239.     AddAttachment(NEW LCMAttachment);
  240. }
  241.  
  242.  
  243. // ---------------------------------------------------------------------------
  244. //    • ~MultiMonitorApp                                    [public, virtual]
  245. // ---------------------------------------------------------------------------
  246. //    Application object destructor
  247.  
  248. MultiMonitorApp::~MultiMonitorApp()
  249. {
  250.         // Clean up after Standard Dialogs
  251.     PP_StandardDialogs::Unload();
  252. }
  253.  
  254.  
  255. // ---------------------------------------------------------------------------
  256. //    • StartUp                                        [protected, virtual]
  257. // ---------------------------------------------------------------------------
  258. //    Perform an action in response to the Open Application AppleEvent.
  259. //    Here, issue the New command to open a window.
  260.  
  261. void
  262. MultiMonitorApp::StartUp()
  263. {
  264.     ObeyCommand(cmd_New, nil);
  265. }
  266.  
  267.  
  268. // ---------------------------------------------------------------------------
  269. //    • ObeyCommand                                    [public, virtual]
  270. // ---------------------------------------------------------------------------
  271. //    Respond to Commands. Returns true if the Command was handled, false if not.
  272.  
  273. Boolean
  274. MultiMonitorApp::ObeyCommand(
  275.     CommandT    inCommand,
  276.     void *        ioParam)
  277. {
  278.     Boolean        cmdHandled = true;    // Assume we'll handle the command
  279.  
  280.     switch (inCommand) {
  281.  
  282.     #if PP_Debug
  283.         case cmd_DoTest: {
  284.             DoTest();
  285.             break;
  286.         }
  287.     #endif
  288.  
  289.         default: {
  290.             cmdHandled = LDocApplication::ObeyCommand(inCommand, ioParam);
  291.             break;
  292.         }
  293.     }
  294.     
  295.     return cmdHandled;
  296. }
  297.  
  298.  
  299. // ---------------------------------------------------------------------------
  300. //    • FindCommandStatus                                [public, virtual]
  301. // ---------------------------------------------------------------------------
  302. //    Determine the status of a Command for the purposes of menu updating.
  303.  
  304. void
  305. MultiMonitorApp::FindCommandStatus(
  306.     CommandT    inCommand,
  307.     Boolean&    outEnabled,
  308.     Boolean&    outUsesMark,
  309.     UInt16&        outMark,
  310.     Str255        outName)
  311. {
  312.     switch (inCommand) {
  313.  
  314.     #if PP_Debug
  315.         case cmd_DoTest: {
  316.             outEnabled = true;
  317.             break;
  318.         }
  319.     #endif
  320.  
  321.         default: {
  322.             LDocApplication::FindCommandStatus(inCommand, outEnabled,
  323.                                             outUsesMark, outMark, outName);
  324.             break;
  325.         }
  326.     }
  327. }
  328.  
  329.  
  330. // ---------------------------------------------------------------------------
  331. //    • Initialize
  332. // ---------------------------------------------------------------------------
  333. //    Here we do a few interesting things.
  334. //
  335. //    1.    Flush any pending events. I have seen times where if you launch
  336. //        your app and then immediately hit a menu key combo to cause
  337. //        a window to come up, that can crash! Flushing any such pending
  338. //        events before you're ready to even process them seems to
  339. //        remedy that.
  340. //
  341. //    2.    We create our debug menu attachment. We only need this for the
  342. //        debug build, so we conditionally compile it out.
  343. //
  344. //    3.    We check the version of your application. A bit unnecessary
  345. //        perhaps, but I always found it nice towards ensuring I didn't
  346. //        forget to update my constants and 'vers' resource. Only necessary
  347. //        in the debug build.
  348. //
  349. //    4.    You could do other things here as well: append items to your
  350. //        Help menu, Apple Guide initialization, creating your preferences
  351. //        object, etc.
  352.  
  353. void
  354. MultiMonitorApp::Initialize()
  355. {
  356.     LDocApplication::Initialize();
  357.     
  358.     ::FlushEvents(everyEvent, nil);
  359. }
  360.  
  361. // ---------------------------------------------------------------------------
  362. //    • MakeNewDocument                                [protected, virtual]
  363. // ---------------------------------------------------------------------------
  364. // This method creates a new document and installs it into the application's
  365. // Apple Event Object Model hierarchy.
  366.  
  367. LModelObject*
  368. MultiMonitorApp::MakeNewDocument()
  369. {
  370.         // Make a new empty document.
  371.     MultiMonitorDoc *    theDoc = NEW MultiMonitorDoc(this);
  372.     ValidateObject_(theDoc);
  373.     
  374.     NEW MultiMonitorController();
  375.     
  376.     return theDoc;
  377. }
  378.  
  379.  
  380. // ---------------------------------------------------------------------------
  381. //    • RegisterClasses                                [protected]
  382. // ---------------------------------------------------------------------------
  383. //    To reduce clutter within the Application object's constructor, class
  384. //    registrations appear here in this seperate function for ease of use.
  385.  
  386. void
  387. MultiMonitorApp::RegisterClasses()
  388. {
  389.         // Register debugging classes
  390. #if PP_Debug
  391.     RegisterClass_(LCommanderTree);
  392.     RegisterClass_(LPaneTree);
  393.     RegisterClass_(LTreeWindow);
  394. #endif
  395.  
  396.         // Register core PowerPlant classes.
  397.     RegisterClass_(LWindow);
  398.     RegisterClass_(LPrintout);
  399.     RegisterClass_(LPlaceHolder);
  400.     RegisterClass_(LKeyScrollAttachment);
  401.     RegisterClass_(LColorEraseAttachment);
  402.     RegisterClass_(LCMAttachment);
  403.     RegisterClass_(LUndoer);
  404.  
  405.         // Register the Appearance Manager/GA classes. You may want
  406.         // to remove this use of UControlRegistry and instead perform
  407.         // a "manual" registration of the classes. This cuts down on
  408.         // extra code being linked in and streamlines your app and
  409.         // project. However, use UControlRegistry as a reference/index
  410.         // for your work, and ensure to check UControlRegistry against
  411.         // your registrations each PowerPlant release in case
  412.         // any mappings might have changed.
  413.         
  414.     UControlRegistry::RegisterClasses();
  415. }
  416.  
  417.  
  418. // ---------------------------------------------------------------------------
  419. //    • DoTest                                        [public]
  420. // ---------------------------------------------------------------------------
  421. //    A handy place to insert test code (i.e. you want to try some code out
  422. //    and just need a place to put it).
  423.  
  424. void
  425. MultiMonitorApp::DoTest()
  426. {
  427.     SignalStringLiteral_("Insert your test code here");    
  428. }